home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Python 1.3.3 / Python 133 SRC / Modules / _tkinter.c next >
Text File  |  1996-03-06  |  29KB  |  1,390 lines

  1. /* _tkinter.c -- Interface to libtk.a and libtcl.a.
  2.    Copyright (C) 1994 Steen Lumholt */
  3.  
  4. #include "Python.h"
  5.  
  6. #include <tcl.h>
  7. #include <tk.h>
  8.  
  9. extern char *getprogramname ();
  10.  
  11. /* Internal declarations from tkInt.h.  */
  12. #if (TK_MAJOR_VERSION*1000 + TK_MINOR_VERSION) >= 4001
  13. extern int Tk_GetNumMainWindows();
  14. #else
  15. extern int tk_NumMainWindows;
  16. #define Tk_GetNumMainWindows() (tk_NumMainWindows)
  17. #define NEED_TKCREATEMAINWINDOW 1
  18. #endif
  19.  
  20. #if TK_MAJOR_VERSION < 4
  21. extern struct { Tk_Window win; } *tkMainWindowList;
  22. #endif
  23.  
  24. #ifdef macintosh
  25.  
  26. /*
  27. ** Additional cruft needed by Tcl/Tk on the Mac.
  28. ** Unfortunately this changes with each beta.
  29. ** This is for beta 2 of Tcl 7.5 and Tk 4.1.
  30. */
  31.  
  32. #include <Events.h> /* For EventRecord */
  33.  
  34. typedef int (*TclMacConvertEventPtr) Py_PROTO((EventRecord *eventPtr));
  35. void TclMacSetEventProc Py_PROTO((TclMacConvertEventPtr procPtr));
  36. int TkMacConvertEvent Py_PROTO((EventRecord *eventPtr));
  37.  
  38. staticforward int PyMacConvertEvent Py_PROTO((EventRecord *eventPtr));
  39.  
  40. #endif /* macintosh */
  41.  
  42. /**** Tkapp Object Declaration ****/
  43.  
  44. staticforward PyTypeObject Tkapp_Type;
  45.  
  46. typedef struct
  47.   {
  48.     PyObject_HEAD
  49.     Tcl_Interp *interp;
  50. #ifdef NEED_TKCREATEMAINWINDOW
  51.     Tk_Window tkwin;
  52. #endif
  53.   }
  54. TkappObject;
  55.  
  56. #define Tkapp_Check(v) ((v)->ob_type == &Tkapp_Type)
  57. #ifdef NEED_TKCREATEMAINWINDOW
  58. #define Tkapp_Tkwin(v)  (((TkappObject *) (v))->tkwin)
  59. #endif
  60. #define Tkapp_Interp(v) (((TkappObject *) (v))->interp)
  61. #define Tkapp_Result(v) (((TkappObject *) (v))->interp->result)
  62.  
  63. #define DEBUG_REFCNT(v) (printf ("DEBUG: id=%p, refcnt=%i\n", \
  64.                  (void *) v, ((PyObject *) v)->ob_refcnt))
  65.  
  66. /**** Error Handling ****/
  67.  
  68. static PyObject *Tkinter_TclError;
  69. static int quitMainLoop = 0;
  70. static int errorInCmd = 0;
  71. static PyObject *excInCmd;
  72. static PyObject *valInCmd;
  73. static PyObject *trbInCmd;
  74.  
  75. static PyObject *
  76. Tkinter_Error (v)
  77.      PyObject *v;
  78. {
  79.   PyErr_SetString (Tkinter_TclError, Tkapp_Result (v));
  80.   return NULL;
  81. }
  82.  
  83. int
  84. PythonCmd_Error (interp)
  85.      Tcl_Interp *interp;
  86. {
  87.   errorInCmd = 1;
  88.   PyErr_Fetch (&excInCmd, &valInCmd, &trbInCmd);
  89.   return TCL_ERROR;
  90. }
  91.  
  92. /**** Utils ****/
  93.  
  94. static char *
  95. AsString (value, tmp)
  96.      PyObject *value;
  97.      PyObject *tmp;
  98. {
  99.   if (PyString_Check (value))
  100.     return PyString_AsString (value);
  101.   else
  102.     {
  103.       PyObject *v;
  104.  
  105.       v = PyObject_Str (value);
  106.       PyList_Append (tmp, v);
  107.       Py_DECREF (v);
  108.       return PyString_AsString (v);
  109.     }
  110. }
  111.  
  112. #define ARGSZ 64
  113.  
  114. static char *
  115. Merge (args)
  116.      PyObject *args;
  117. {
  118.   PyObject *tmp;
  119.   char *argvStore[ARGSZ];
  120.   char **argv;
  121.   int fvStore[ARGSZ];
  122.   int *fv;
  123.   int argc;
  124.   char *res;
  125.   int i;
  126.  
  127.   tmp = PyList_New (0);
  128.   argv = argvStore;
  129.   fv = fvStore;
  130.  
  131.   if (!PyTuple_Check (args))
  132.     {
  133.       argc = 1;
  134.       fv[0] = 0;
  135.       argv[0] = AsString (args, tmp);
  136.     }
  137.   else
  138.     {
  139.       PyObject *v;
  140.  
  141.       if (PyTuple_Size (args) > ARGSZ)
  142.     {
  143.       argv = (char **) malloc (PyTuple_Size (args) * sizeof (char *));
  144.       fv = (int *) malloc (PyTuple_Size (args) * sizeof (int));
  145.       if (argv == NULL || fv == NULL)
  146.         PyErr_NoMemory ();
  147.     }
  148.  
  149.       argc = PyTuple_Size (args);
  150.       for (i = 0; i < argc; i++)
  151.     {
  152.       v = PyTuple_GetItem (args, i);
  153.       if (PyTuple_Check (v))
  154.         {
  155.           fv[i] = 1;
  156.           argv[i] = Merge (v);
  157.         }
  158.       else if (v == Py_None)
  159.         {
  160.           argc = i;
  161.           break;
  162.         }
  163.       else
  164.         {
  165.           fv[i] = 0;
  166.           argv[i] = AsString (v, tmp);
  167.         }
  168.     }
  169.     }
  170.  
  171.   res = Tcl_Merge (argc, argv);
  172.  
  173.   Py_DECREF (tmp);
  174.   for (i = 0; i < argc; i++)
  175.     if (fv[i]) free (argv[i]);
  176.   if (argv != argvStore)
  177.     free (argv);
  178.   if (fv != fvStore)
  179.     free (fv);
  180.  
  181.   return res;
  182. }
  183.  
  184. static PyObject *
  185. Split (self, list)
  186.      PyObject *self;
  187.      char *list;
  188. {
  189.   int argc;
  190.   char **argv;
  191.   PyObject *v;
  192.  
  193.   if (list == NULL)
  194.     {
  195.       Py_INCREF (Py_None);
  196.       return Py_None;
  197.     }
  198.  
  199.   if (Tcl_SplitList (Tkapp_Interp (self), list, &argc, &argv) == TCL_ERROR)
  200.     return Tkinter_Error (self);
  201.  
  202.   if (argc == 0)
  203.     v = PyString_FromString ("");
  204.   else if (argc == 1)
  205.     v = PyString_FromString (argv[0]);
  206.   else
  207.     {
  208.       int i;
  209.  
  210.       v = PyTuple_New (argc);
  211.       for (i = 0; i < argc; i++)
  212.     PyTuple_SetItem (v, i, Split (self, argv[i]));
  213.     }
  214.  
  215.   free (argv);
  216.   return v;
  217. }
  218.  
  219. /**** Tkapp Object ****/
  220.  
  221. #ifndef WITH_APPINIT
  222. int
  223. Tcl_AppInit (interp)
  224.      Tcl_Interp *interp;
  225. {
  226.   Tk_Window main;
  227.  
  228.   main = Tk_MainWindow(interp);
  229.   if (Tcl_Init (interp) == TCL_ERROR) {
  230.     fprintf(stderr, "Tcl_Init error: %s\n", interp->result);
  231.     return TCL_ERROR;
  232.   }
  233.   if (Tk_Init (interp) == TCL_ERROR) {
  234.     fprintf(stderr, "Tk_Init error: %s\n", interp->result);
  235.     return TCL_ERROR;
  236.   }
  237.   return TCL_OK;
  238. }
  239.  
  240. char *
  241. TkDefaultAppName()
  242. {
  243.     return "Python";
  244. }
  245.  
  246. #endif /* !WITH_APPINIT */
  247.  
  248. /* Initialize the Tk application; see the `main' function in
  249.    `tkMain.c'.  */
  250. static TkappObject *
  251. Tkapp_New (screenName, baseName, className, interactive)
  252.      char *screenName;
  253.      char *baseName;
  254.      char *className;
  255.      int interactive;
  256. {
  257.   TkappObject *v;
  258.   
  259.   v = PyObject_NEW (TkappObject, &Tkapp_Type);
  260.   if (v == NULL)
  261.     return NULL;
  262.  
  263.   v->interp = Tcl_CreateInterp ();
  264.  
  265. #ifdef NEED_TKCREATEMAINWINDOW
  266.   v->tkwin = Tk_CreateMainWindow (v->interp, screenName, 
  267.                   baseName, className);
  268.   if (v->tkwin == NULL)
  269.     return (TkappObject *) Tkinter_Error ((PyObject *) v);
  270.  
  271.   Tk_GeometryRequest (v->tkwin, 200, 200);
  272. #endif
  273.  
  274.   if (screenName != NULL)
  275.     Tcl_SetVar2 (v->interp, "env", "DISPLAY", screenName, TCL_GLOBAL_ONLY);
  276.  
  277.   if (interactive)
  278.     Tcl_SetVar (v->interp, "tcl_interactive", "1", TCL_GLOBAL_ONLY);
  279.   else
  280.     Tcl_SetVar (v->interp, "tcl_interactive", "0", TCL_GLOBAL_ONLY);
  281.  
  282.   if (Tcl_AppInit (v->interp) != TCL_OK)
  283.     {
  284.       PyErr_SetString (Tkinter_TclError, "Tcl_AppInit failed"); /* XXX */
  285.       return NULL;
  286.     }
  287.  
  288.   return v;
  289. }
  290.  
  291. /** Tcl Eval **/
  292.  
  293. static PyObject *
  294. Tkapp_Call (self, args)
  295.      PyObject *self;
  296.      PyObject *args;
  297. {
  298.   char *cmd;
  299.  
  300.   cmd = Merge (args);
  301.   if (Tcl_Eval (Tkapp_Interp (self), cmd) == TCL_ERROR)
  302.     {
  303.       free (cmd);
  304.       return Tkinter_Error (self);
  305.     }
  306.  
  307.   free (cmd);
  308.   return PyString_FromString (Tkapp_Result (self));
  309. }
  310.  
  311. static PyObject *
  312. Tkapp_GlobalCall (self, args)
  313.      PyObject *self;
  314.      PyObject *args;
  315. {
  316.   char *cmd;
  317.  
  318.   cmd = Merge (args);
  319.   if (Tcl_GlobalEval (Tkapp_Interp (self), cmd) == TCL_ERROR)
  320.     {
  321.       free (cmd);
  322.       return Tkinter_Error (self);
  323.     }
  324.   
  325.   free (cmd);
  326.   return PyString_FromString (Tkapp_Result (self));
  327. }
  328.  
  329. static PyObject *
  330. Tkapp_Eval (self, args)
  331.      PyObject *self;
  332.      PyObject *args;
  333. {
  334.   char *script;
  335.   
  336.   if (!PyArg_Parse (args, "s", &script))
  337.     return NULL;
  338.  
  339.   if (Tcl_Eval (Tkapp_Interp (self), script) == TCL_ERROR)
  340.     return Tkinter_Error (self);
  341.   
  342.   return PyString_FromString (Tkapp_Result (self));
  343. }
  344.  
  345. static PyObject *
  346. Tkapp_GlobalEval (self, args)
  347.      PyObject *self;
  348.      PyObject *args;
  349. {
  350.   char *script;
  351.   
  352.   if (!PyArg_Parse (args, "s", &script))
  353.     return NULL;
  354.  
  355.   if (Tcl_GlobalEval (Tkapp_Interp (self), script) == TCL_ERROR)
  356.     return Tkinter_Error (self);
  357.  
  358.   return PyString_FromString (Tkapp_Result (self));
  359. }
  360.  
  361. static PyObject *
  362. Tkapp_EvalFile (self, args)
  363.      PyObject *self;
  364.      PyObject *args;
  365. {
  366.   char *fileName;
  367.  
  368.   if (!PyArg_Parse (args, "s", &fileName))
  369.     return NULL;
  370.  
  371.   if (Tcl_EvalFile (Tkapp_Interp (self), fileName) == TCL_ERROR)
  372.     return Tkinter_Error (self);
  373.  
  374.   return PyString_FromString (Tkapp_Result (self));
  375. }
  376.  
  377. static PyObject *
  378. Tkapp_Record (self, args)
  379.      PyObject *self;
  380.      PyObject *args;
  381. {
  382.   char *script;
  383.  
  384.   if (!PyArg_Parse (args, "s", &script))
  385.     return NULL;
  386.  
  387.   if (Tcl_RecordAndEval (Tkapp_Interp (self), 
  388.              script, TCL_NO_EVAL) == TCL_ERROR)
  389.     return Tkinter_Error (self);
  390.  
  391.   return PyString_FromString (Tkapp_Result (self));
  392. }
  393.  
  394. static PyObject *
  395. Tkapp_AddErrorInfo (self, args)
  396.      PyObject *self;
  397.      PyObject *args;
  398. {
  399.   char *msg;
  400.  
  401.   if (!PyArg_Parse (args, "s", &msg))
  402.     return NULL;
  403.   Tcl_AddErrorInfo (Tkapp_Interp (self), msg);
  404.  
  405.   Py_INCREF(Py_None);
  406.   return Py_None;
  407. }
  408.  
  409. /** Tcl Variable **/
  410.  
  411. static PyObject *
  412. SetVar (self, args, flags)
  413.      PyObject *self;
  414.      PyObject *args;
  415.      int flags;
  416. {
  417.   char *name1, *name2, *ok;
  418.   PyObject *newValue;
  419.   PyObject *tmp;
  420.  
  421.   tmp = PyList_New (0);
  422.  
  423.   if (PyArg_Parse (args, "(sO)", &name1, &newValue))
  424.     ok = Tcl_SetVar (Tkapp_Interp (self), name1, 
  425.              AsString (newValue, tmp), flags); /* XXX Merge? */
  426.   else if (PyArg_Parse (args, "(ssO)", &name1, &name2, &newValue))
  427.     ok = Tcl_SetVar2 (Tkapp_Interp (self), name1, name2, 
  428.               AsString (newValue, tmp), flags);
  429.   else
  430.     {
  431.       Py_DECREF (tmp);
  432.       return NULL;
  433.     }
  434.   Py_DECREF (tmp);
  435.  
  436.   if (!ok)
  437.     return Tkinter_Error (self);
  438.  
  439.   Py_INCREF (Py_None);
  440.   return Py_None;
  441. }
  442.  
  443. static PyObject *
  444. Tkapp_SetVar (self, args)
  445.      PyObject *self;
  446.      PyObject *args;
  447. {
  448.   return SetVar (self, args, TCL_LEAVE_ERR_MSG);
  449. }
  450.  
  451. static PyObject *
  452. Tkapp_GlobalSetVar (self, args)
  453.      PyObject *self;
  454.      PyObject *args;
  455. {
  456.   return SetVar (self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
  457. }
  458.  
  459. static PyObject *
  460. GetVar (self, args, flags)
  461.      PyObject *self;
  462.      PyObject *args;
  463.      int flags;
  464. {
  465.   char *name1, *name2, *s;
  466.  
  467.   if (PyArg_Parse (args, "s", &name1))
  468.     s = Tcl_GetVar (Tkapp_Interp (self), name1, flags);
  469.   else if (PyArg_Parse (args, "(ss)", &name1, &name2))
  470.     s = Tcl_GetVar2 (Tkapp_Interp (self), name1, name2, flags);
  471.   else
  472.     return NULL;
  473.  
  474.   if (s == NULL)
  475.     return Tkinter_Error (self);
  476.  
  477.   return PyString_FromString (s);
  478. }
  479.  
  480. static PyObject *
  481. Tkapp_GetVar (self, args)
  482.      PyObject *self;
  483.      PyObject *args;
  484. {
  485.   return GetVar (self, args, TCL_LEAVE_ERR_MSG);
  486. }
  487.  
  488. static PyObject *
  489. Tkapp_GlobalGetVar (self, args)
  490.      PyObject *self;
  491.      PyObject *args;
  492. {
  493.   return GetVar (self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
  494. }
  495.  
  496. static PyObject *
  497. UnsetVar (self, args, flags)
  498.      PyObject *self;
  499.      PyObject *args;
  500.      int flags;
  501. {
  502.   char *name1, *name2;
  503.   int code;
  504.  
  505.   if (PyArg_Parse (args, "s", &name1))
  506.     code = Tcl_UnsetVar (Tkapp_Interp (self), name1, flags);
  507.   else if (PyArg_Parse (args, "(ss)", &name1, &name2))
  508.     code = Tcl_UnsetVar2 (Tkapp_Interp (self), name1, name2, flags);
  509.   else
  510.     return NULL;
  511.  
  512.   if (code == TCL_ERROR)
  513.     return Tkinter_Error (self);
  514.  
  515.   Py_INCREF (Py_None);
  516.   return Py_None;
  517. }
  518.  
  519. static PyObject *
  520. Tkapp_UnsetVar (self, args)
  521.      PyObject *self;
  522.      PyObject *args;
  523. {
  524.   return UnsetVar (self, args, TCL_LEAVE_ERR_MSG);
  525. }
  526.  
  527. static PyObject *
  528. Tkapp_GlobalUnsetVar (self, args)
  529.      PyObject *self;
  530.      PyObject *args;
  531. {
  532.   return UnsetVar (self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY);
  533. }
  534.  
  535. /** Tcl to Python **/
  536.  
  537. static PyObject *
  538. Tkapp_GetInt (self, args)
  539.      PyObject *self;
  540.      PyObject *args;
  541. {
  542.   char *s;
  543.   int v;
  544.  
  545.   if (!PyArg_Parse (args, "s", &s))
  546.     return NULL;
  547.   if (Tcl_GetInt (Tkapp_Interp (self), s, &v) == TCL_ERROR)
  548.     return Tkinter_Error (self);
  549.   return Py_BuildValue ("i", v);
  550. }
  551.  
  552. static PyObject *
  553. Tkapp_GetDouble (self, args)
  554.      PyObject *self;
  555.      PyObject *args;
  556. {
  557.   char *s;
  558.   double v;
  559.  
  560.   if (!PyArg_Parse (args, "s", &s))
  561.     return NULL;
  562.   if (Tcl_GetDouble (Tkapp_Interp (self), s, &v) == TCL_ERROR)
  563.     return Tkinter_Error (self);
  564.   return Py_BuildValue ("d", v);
  565. }
  566.  
  567. static PyObject *
  568. Tkapp_GetBoolean (self, args)
  569.      PyObject *self;
  570.      PyObject *args;
  571. {
  572.   char *s;
  573.   int v;
  574.  
  575.   if (!PyArg_Parse (args, "s", &s))
  576.     return NULL;
  577.   if (Tcl_GetBoolean (Tkapp_Interp (self), s, &v) == TCL_ERROR)
  578.     return Tkinter_Error (self);
  579.   return Py_BuildValue ("i", v);
  580. }
  581.  
  582. static PyObject *
  583. Tkapp_ExprString (self, args)
  584.      PyObject *self;
  585.      PyObject *args;
  586. {
  587.   char *s;
  588.  
  589.   if (!PyArg_Parse (args, "s", &s))
  590.     return NULL;
  591.   if (Tcl_ExprString (Tkapp_Interp (self), s) == TCL_ERROR)
  592.     return Tkinter_Error (self);
  593.   return Py_BuildValue ("s", Tkapp_Result (self));
  594. }
  595.  
  596. static PyObject *
  597. Tkapp_ExprLong (self, args)
  598.      PyObject *self;
  599.      PyObject *args;
  600. {
  601.   char *s;
  602.   long v;
  603.  
  604.   if (!PyArg_Parse (args, "s", &s))
  605.     return NULL;
  606.   if (Tcl_ExprLong (Tkapp_Interp (self), s, &v) == TCL_ERROR)
  607.     return Tkinter_Error (self);
  608.   return Py_BuildValue ("l", v);
  609. }
  610.  
  611. static PyObject *
  612. Tkapp_ExprDouble (self, args)
  613.      PyObject *self;
  614.      PyObject *args;
  615. {
  616.   char *s;
  617.   double v;
  618.  
  619.   if (!PyArg_Parse (args, "s", &s))
  620.     return NULL;
  621.   if (Tcl_ExprDouble (Tkapp_Interp (self), s, &v) == TCL_ERROR)
  622.     return Tkinter_Error (self);
  623.   return Py_BuildValue ("d", v);
  624. }
  625.  
  626. static PyObject *
  627. Tkapp_ExprBoolean (self, args)
  628.      PyObject *self;
  629.      PyObject *args;
  630. {
  631.   char *s;
  632.   int v;
  633.  
  634.   if (!PyArg_Parse (args, "s", &s))
  635.     return NULL;
  636.   if (Tcl_ExprBoolean (Tkapp_Interp (self), s, &v) == TCL_ERROR)
  637.     return Tkinter_Error (self);
  638.   return Py_BuildValue ("i", v);
  639. }
  640.  
  641. static PyObject *
  642. Tkapp_SplitList (self, args)
  643.      PyObject *self;
  644.      PyObject *args;
  645. {
  646.   char *list;
  647.   int argc;
  648.   char **argv;
  649.   PyObject *v;
  650.   int i;
  651.  
  652.   if (!PyArg_Parse (args, "s", &list))
  653.     return NULL;
  654.  
  655.   if (Tcl_SplitList (Tkapp_Interp (self), list, &argc, &argv) == TCL_ERROR)
  656.     return Tkinter_Error (self);
  657.  
  658.   v = PyTuple_New (argc);
  659.   for (i = 0; i < argc; i++)
  660.     PyTuple_SetItem (v, i, PyString_FromString (argv[i]));
  661.  
  662.   free (argv);
  663.   return v;
  664. }
  665.  
  666. static PyObject *
  667. Tkapp_Split (self, args)
  668.      PyObject *self;
  669.      PyObject *args;
  670. {
  671.   char *list;
  672.  
  673.   if (!PyArg_Parse (args, "s", &list))
  674.     return NULL;
  675.   return Split (self, list);
  676. }
  677.  
  678. static PyObject *
  679. Tkapp_Merge (self, args)
  680.      PyObject *self;
  681.      PyObject *args;
  682. {
  683.   char *s;
  684.   PyObject *v;
  685.  
  686.   s = Merge (args);
  687.   v = PyString_FromString (s);
  688.   free (s);
  689.   return v;
  690. }
  691.  
  692. /** Tcl Command **/
  693.  
  694. /* This is the Tcl command that acts as a wrapper for Python
  695.    function or method.  */
  696. static int
  697. PythonCmd (clientData, interp, argc, argv)
  698.      ClientData clientData;    /* Is (self, func) */
  699.      Tcl_Interp *interp;
  700.      int argc;
  701.      char *argv[];
  702. {
  703.   PyObject *self, *func, *arg, *res, *tmp;
  704.   int i;
  705.  
  706.   self = PyTuple_GetItem ((PyObject *) clientData, 0);
  707.   func = PyTuple_GetItem ((PyObject *) clientData, 1);
  708.  
  709.   /* Create argument list (argv1, ..., argvN) */
  710.   arg = PyTuple_New (argc - 1);
  711.   for (i = 0; i < (argc - 1); i++)
  712.     PyTuple_SetItem (arg, i, PyString_FromString (argv[i + 1]));
  713.   
  714.   res = PyEval_CallObject (func, arg);
  715.   Py_DECREF (arg);
  716.  
  717.   if (res == NULL)
  718.     return PythonCmd_Error (interp);
  719.  
  720.   tmp = PyList_New (0);
  721.   Tcl_SetResult (Tkapp_Interp (self), AsString (res, tmp), TCL_VOLATILE);
  722.   Py_DECREF (res);
  723.   Py_DECREF (tmp);
  724.  
  725.   return TCL_OK;
  726. }
  727.  
  728. static void
  729. PythonCmdDelete (clientData)
  730.      ClientData clientData;    /* Is (self, func) */
  731. {
  732.   Py_DECREF ((PyObject *) clientData);
  733. }
  734.  
  735. static PyObject *
  736. Tkapp_CreateCommand (self, args)
  737.      PyObject *self;
  738.      PyObject *args;
  739. {
  740.   char *cmdName;
  741.   PyObject *data;
  742.   PyObject *func;
  743.   
  744.   /* Args is: (cmdName, func) */
  745.   if (!PyTuple_Check (args) 
  746.       || !(PyTuple_Size (args) == 2)
  747.       || !PyString_Check (PyTuple_GetItem (args, 0))
  748.       || !PyCallable_Check (PyTuple_GetItem (args, 1)))
  749.     {
  750.       PyErr_SetString (PyExc_TypeError, "bad argument list");
  751.       return NULL;
  752.     }
  753.  
  754.   cmdName = PyString_AsString (PyTuple_GetItem (args, 0));
  755.   func = PyTuple_GetItem (args, 1);
  756.  
  757.   data = PyTuple_New (2);   /* ClientData is: (self, func) */
  758.  
  759.   Py_INCREF (self);
  760.   PyTuple_SetItem (data, 0, self);
  761.  
  762.   Py_INCREF (func);
  763.   PyTuple_SetItem (data, 1, func);
  764.  
  765.   Tcl_CreateCommand (Tkapp_Interp (self), cmdName, PythonCmd,
  766.              (ClientData) data, PythonCmdDelete);
  767.  
  768.   Py_INCREF (Py_None);
  769.   return Py_None;
  770. }
  771.  
  772. static PyObject *
  773. Tkapp_DeleteCommand (self, args)
  774.      PyObject *self;
  775.      PyObject *args;
  776. {
  777.   char *cmdName;
  778.  
  779.   if (!PyArg_Parse (args, "s", &cmdName))
  780.     return NULL;
  781.   if (Tcl_DeleteCommand (Tkapp_Interp (self), cmdName) == -1)
  782.     {
  783.       PyErr_SetString (Tkinter_TclError, "can't delete Tcl command");
  784.       return NULL;
  785.     }
  786.   Py_INCREF (Py_None);
  787.   return Py_None;
  788. }
  789.  
  790. /** File Handler **/
  791.  
  792. static void
  793. FileHandler (clientData, mask)
  794.      ClientData clientData;    /* Is: (func, file) */
  795.      int mask;
  796. {
  797.   PyObject *func, *file, *arg, *res;
  798.  
  799.   func = PyTuple_GetItem ((PyObject *) clientData, 0);
  800.   file = PyTuple_GetItem ((PyObject *) clientData, 1);
  801.  
  802.   arg = Py_BuildValue ("(Oi)", file, (long) mask);
  803.   res = PyEval_CallObject (func, arg);
  804.   Py_DECREF (arg);
  805.   if (res == NULL)
  806.     {
  807.       errorInCmd = 1;
  808.       PyErr_Fetch (&excInCmd, &valInCmd, &trbInCmd);
  809.     }
  810.   Py_XDECREF (res);
  811. }
  812.  
  813. static int
  814. GetFileNo (file)
  815.     PyObject *file; /* Either an int >= 0 or an object with a
  816.                .fileno() method that returns an int >= 0 */
  817. {
  818.     PyObject *meth, *args, *res;
  819.     int id;
  820.     if (PyInt_Check(file)) {
  821.         id = PyInt_AsLong(file);
  822.         if (id < 0)
  823.             PyErr_SetString(PyExc_ValueError, "invalid file id");
  824.         return id;
  825.     }
  826.     meth = PyObject_GetAttrString(file, "fileno");
  827.     if (meth == NULL)
  828.         return -1;
  829.     args = PyTuple_New(0);
  830.     if (args == NULL)
  831.         return -1;
  832.     res = PyEval_CallObject(meth, args);
  833.     Py_DECREF(args);
  834.     Py_DECREF(meth);
  835.     if (res == NULL)
  836.         return -1;
  837.     if (PyInt_Check(res))
  838.         id = PyInt_AsLong(res);
  839.     else
  840.         id = -1;
  841.     if (id < 0)
  842.         PyErr_SetString(PyExc_ValueError,
  843.                 "invalid fileno() return value");
  844.     Py_DECREF(res);
  845.     return id;
  846. }
  847.  
  848. static PyObject *
  849. Tkapp_CreateFileHandler (self, args)
  850.      PyObject *self;
  851.      PyObject *args;        /* Is (file, mask, func) */
  852. {
  853.   PyObject *file, *func, *data;
  854.   int mask, id;
  855.  
  856.   if (!PyArg_Parse (args, "(OiO)", &file, &mask, &func))
  857.     return NULL;
  858.   id = GetFileNo (file);
  859.   if (id < 0)
  860.     return NULL;
  861.   if (!PyCallable_Check(func))
  862.     {
  863.       PyErr_SetString (PyExc_TypeError, "bad argument list");
  864.       return NULL;
  865.     }
  866.  
  867.   /* ClientData is: (func, file) */
  868.   data = Py_BuildValue ("(OO)", func, file);
  869.  
  870.   Tk_CreateFileHandler ((ClientData) id, mask, FileHandler, (ClientData) data);
  871.   /* XXX fileHandlerDict */
  872.  
  873.   Py_INCREF (Py_None);
  874.   return Py_None;
  875. }
  876.  
  877. static PyObject *
  878. Tkapp_DeleteFileHandler (self, args)
  879.      PyObject *self;
  880.      PyObject *args;        /* Args: file */
  881. {
  882.   PyObject *file;
  883.   int id;
  884.  
  885.   if (!PyArg_Parse (args, "O", &file))
  886.     return NULL;
  887.   id = GetFileNo (file);
  888.   if (id < 0)
  889.     return NULL;
  890.  
  891.   Tk_DeleteFileHandler ((ClientData) id);
  892.   /* XXX fileHandlerDict */
  893.   Py_INCREF (Py_None);
  894.   return Py_None;
  895. }
  896.  
  897. /**** Tktt Object (timer token) ****/
  898.  
  899. staticforward PyTypeObject Tktt_Type;
  900.  
  901. typedef struct
  902.   {
  903.     PyObject_HEAD
  904.     Tk_TimerToken token;
  905.     PyObject *func;
  906.   }
  907. TkttObject;
  908.  
  909. static PyObject *
  910. Tktt_DeleteTimerHandler (self, args)
  911.      PyObject *self;
  912.      PyObject *args;
  913. {
  914.   TkttObject *v = (TkttObject *) self;
  915.  
  916.   if (!PyArg_Parse (args, ""))
  917.     return NULL;
  918.   if (v->func != NULL)
  919.     {
  920.       Tk_DeleteTimerHandler (v->token);
  921.       PyMem_DEL (v->func);
  922.       v->func = NULL;
  923.     }
  924.   Py_INCREF (Py_None);
  925.   return Py_None;
  926. }
  927.  
  928. static PyMethodDef Tktt_methods[] =
  929. {
  930.   {"deletetimerhandler", Tktt_DeleteTimerHandler},
  931.   {NULL, NULL}
  932. };
  933.  
  934. static TkttObject *
  935. Tktt_New (token, func)
  936.      Tk_TimerToken token;
  937.      PyObject *func;
  938. {
  939.   TkttObject *v;
  940.   
  941.   v = PyObject_NEW (TkttObject, &Tktt_Type);
  942.   if (v == NULL)
  943.     return NULL;
  944.  
  945.   v->token = token;
  946.   v->func = func;
  947.   Py_INCREF (v->func);
  948.   return v;
  949. }
  950.  
  951. static void
  952. Tktt_Dealloc (self)
  953.      PyObject *self;
  954. {
  955.   PyMem_DEL (self);
  956. }
  957.  
  958. static int
  959. Tktt_Print (self, fp, flags)
  960.      PyObject *self;
  961.      FILE *fp;
  962.      int flags;
  963. {
  964.   TkttObject *v = (TkttObject *) self;
  965.  
  966.   fprintf(fp, "<tktimertoken at 0x%x%s>", v,
  967.     v->func == NULL ? ", handler deleted" : "");
  968.   return 0;
  969. }
  970.  
  971. static PyObject *
  972. Tktt_GetAttr (self, name)
  973.      PyObject *self;
  974.      char *name;
  975. {
  976.   return Py_FindMethod (Tktt_methods, self, name);
  977. }
  978.  
  979. static PyTypeObject Tktt_Type =
  980. {
  981.   PyObject_HEAD_INIT (&PyType_Type)
  982.   0,                /*ob_size */
  983.   "tktimertoken",        /*tp_name */
  984.   sizeof (TkttObject),        /*tp_basicsize */
  985.   0,                /*tp_itemsize */
  986.   Tktt_Dealloc,            /*tp_dealloc */
  987.   Tktt_Print,            /*tp_print */
  988.   Tktt_GetAttr,            /*tp_getattr */
  989.   0,                /*tp_setattr */
  990.   0,                /*tp_compare */
  991.   0,                /*tp_repr */
  992.   0,                /*tp_as_number */
  993.   0,                /*tp_as_sequence */
  994.   0,                /*tp_as_mapping */
  995.   0,                /*tp_hash */
  996. };
  997.  
  998. /** Timer Handler **/
  999.  
  1000. static void
  1001. TimerHandler (clientData)
  1002.      ClientData clientData;
  1003. {
  1004.   PyObject *func = (PyObject *) clientData;
  1005.   PyObject *arg, *res;
  1006.  
  1007.   arg = PyTuple_New (0);
  1008.   res = PyEval_CallObject (func, arg);
  1009.   Py_DECREF (arg);
  1010.   if (res == NULL)
  1011.     {
  1012.       errorInCmd = 1;
  1013.       PyErr_Fetch (&excInCmd, &valInCmd, &trbInCmd);
  1014.     }
  1015.   else
  1016.     Py_DECREF (res);
  1017. }
  1018.  
  1019. static PyObject *
  1020. Tkapp_CreateTimerHandler (self, args)
  1021.      PyObject *self;
  1022.      PyObject *args;        /* Is (milliseconds, func) */
  1023. {
  1024.   int milliseconds;
  1025.   PyObject *func;
  1026.   Tk_TimerToken token;
  1027.  
  1028.   if (!PyArg_Parse (args, "(iO)", &milliseconds, &func))
  1029.     return NULL;
  1030.   if (!PyCallable_Check(func))
  1031.     {
  1032.       PyErr_SetString (PyExc_TypeError, "bad argument list");
  1033.       return NULL;
  1034.     }
  1035.   token = Tk_CreateTimerHandler(milliseconds, TimerHandler, (ClientData) func);
  1036.   return (PyObject *) Tktt_New (token, func);
  1037. }
  1038.  
  1039. /** Event Loop **/
  1040.  
  1041. static PyObject *
  1042. Tkapp_MainLoop (self, args)
  1043.      PyObject *self;
  1044.      PyObject *args;
  1045. {
  1046.   int threshold = 0;
  1047.  
  1048.   if (!PyArg_ParseTuple (args, "|i", &threshold))
  1049.     return NULL;
  1050.  
  1051.   quitMainLoop = 0;
  1052.   while (Tk_GetNumMainWindows() > threshold && !quitMainLoop && !errorInCmd)
  1053.     {
  1054.       if (PyOS_InterruptOccurred ())
  1055.     {
  1056.       PyErr_SetNone (PyExc_KeyboardInterrupt);
  1057.       return NULL;
  1058.     }
  1059.       Tk_DoOneEvent (0);
  1060.     }
  1061.   quitMainLoop = 0;
  1062.  
  1063.   if (errorInCmd)
  1064.     {
  1065.       errorInCmd = 0;
  1066.       PyErr_Restore (excInCmd, valInCmd, trbInCmd);
  1067.       excInCmd = valInCmd = trbInCmd = NULL;
  1068.       return NULL;
  1069.     }
  1070.   Py_INCREF (Py_None);
  1071.   return Py_None;
  1072. }
  1073.  
  1074. static PyObject *
  1075. Tkapp_DoOneEvent (self, args)
  1076.     PyObject *self;
  1077.     PyObject *args;
  1078. {
  1079.     int    flags = TK_ALL_EVENTS;
  1080.     int rv;
  1081.  
  1082.     if (!PyArg_ParseTuple (args, "|i", &flags))
  1083.       return NULL;
  1084.     rv = Tk_DoOneEvent(flags);
  1085.     return Py_BuildValue ("i", rv);
  1086. }
  1087.  
  1088. static PyObject *
  1089. Tkapp_Quit (self, args)
  1090.      PyObject *self;
  1091.      PyObject *args;
  1092. {
  1093.  
  1094.   if (!PyArg_Parse (args, ""))
  1095.     return NULL;
  1096.   quitMainLoop = 1;
  1097.   Py_INCREF (Py_None);
  1098.   return Py_None;
  1099. }
  1100.  
  1101. /**** Tkapp Method List ****/
  1102.  
  1103. static PyMethodDef Tkapp_methods[] =
  1104. {
  1105.   {"call", Tkapp_Call},
  1106.   {"globalcall", Tkapp_GlobalCall},
  1107.   {"eval", Tkapp_Eval},
  1108.   {"globaleval", Tkapp_GlobalEval},
  1109.   {"evalfile", Tkapp_EvalFile},
  1110.   {"record", Tkapp_Record},
  1111.   {"adderrorinfo", Tkapp_AddErrorInfo},
  1112.   {"setvar", Tkapp_SetVar},
  1113.   {"globalsetvar", Tkapp_GlobalSetVar},
  1114.   {"getvar", Tkapp_GetVar},
  1115.   {"globalgetvar", Tkapp_GlobalGetVar},
  1116.   {"unsetvar", Tkapp_UnsetVar},
  1117.   {"globalunsetvar", Tkapp_GlobalUnsetVar},
  1118.   {"getint", Tkapp_GetInt},
  1119.   {"getdouble", Tkapp_GetDouble},
  1120.   {"getboolean", Tkapp_GetBoolean},
  1121.   {"exprstring", Tkapp_ExprString},
  1122.   {"exprlong", Tkapp_ExprLong},
  1123.   {"exprdouble", Tkapp_ExprDouble},
  1124.   {"exprboolean", Tkapp_ExprBoolean},
  1125.   {"splitlist", Tkapp_SplitList},
  1126.   {"split", Tkapp_Split},
  1127.   {"merge", Tkapp_Merge},
  1128.   {"createcommand", Tkapp_CreateCommand},
  1129.   {"deletecommand", Tkapp_DeleteCommand},
  1130.   {"createfilehandler", Tkapp_CreateFileHandler},
  1131.   {"deletefilehandler", Tkapp_DeleteFileHandler},
  1132.   {"createtimerhandler", Tkapp_CreateTimerHandler},
  1133.   {"mainloop", Tkapp_MainLoop, 1},
  1134.   {"dooneevent", Tkapp_DoOneEvent, 1},
  1135.   {"quit", Tkapp_Quit},
  1136.   {NULL, NULL}
  1137. };
  1138.  
  1139. /**** Tkapp Type Methods ****/
  1140.  
  1141. static void
  1142. Tkapp_Dealloc (self)
  1143.      PyObject *self;
  1144. {
  1145. #ifdef NEED_TKCREATEMAINWINDOW
  1146.   Tk_DestroyWindow (Tkapp_Tkwin (self));
  1147. #endif
  1148.   Tcl_DeleteInterp (Tkapp_Interp (self));
  1149.   PyMem_DEL (self);
  1150. }
  1151.  
  1152. static PyObject *
  1153. Tkapp_GetAttr (self, name)
  1154.      PyObject *self;
  1155.      char *name;
  1156. {
  1157.   return Py_FindMethod (Tkapp_methods, self, name);
  1158. }
  1159.  
  1160. static PyTypeObject Tkapp_Type =
  1161. {
  1162.   PyObject_HEAD_INIT (&PyType_Type)
  1163.   0,                /*ob_size */
  1164.   "tkapp",            /*tp_name */
  1165.   sizeof (TkappObject),        /*tp_basicsize */
  1166.   0,                /*tp_itemsize */
  1167.   Tkapp_Dealloc,        /*tp_dealloc */
  1168.   0,                /*tp_print */
  1169.   Tkapp_GetAttr,        /*tp_getattr */
  1170.   0,                /*tp_setattr */
  1171.   0,                /*tp_compare */
  1172.   0,                /*tp_repr */
  1173.   0,                /*tp_as_number */
  1174.   0,                /*tp_as_sequence */
  1175.   0,                /*tp_as_mapping */
  1176.   0,                /*tp_hash */
  1177. };
  1178.  
  1179. /**** Tkinter Module ****/
  1180.  
  1181. static PyObject *
  1182. Tkinter_Create (self, args)
  1183.      PyObject *self;
  1184.      PyObject *args;
  1185. {
  1186.   char *screenName = NULL;
  1187.   char *baseName = NULL;
  1188.   char *className = NULL;
  1189.   int interactive = 0;
  1190.  
  1191.   baseName = strrchr (getprogramname (), '/');
  1192.   if (baseName != NULL)
  1193.     baseName++;
  1194.   else
  1195.     baseName = getprogramname ();
  1196.   className = "Tk";
  1197.   
  1198.   if (!PyArg_ParseTuple (args, "|zssi",
  1199.              &screenName, &baseName, &className, &interactive))
  1200.     return NULL;
  1201.  
  1202.   return (PyObject *) Tkapp_New (screenName, baseName, className, 
  1203.                  interactive);
  1204. }
  1205.  
  1206. static PyMethodDef moduleMethods[] =
  1207. {
  1208.   {"create", Tkinter_Create, 1},
  1209.   {"createfilehandler", Tkapp_CreateFileHandler, 0},
  1210.   {"deletefilehandler", Tkapp_DeleteFileHandler, 0},
  1211.   {"createtimerhandler", Tkapp_CreateTimerHandler, 0},
  1212.   {"mainloop", Tkapp_MainLoop, 1},
  1213.   {"dooneevent", Tkapp_DoOneEvent, 1},
  1214.   {"quit", Tkapp_Quit},
  1215.   {NULL, NULL}
  1216. };
  1217.  
  1218. #undef WITH_READLINE /* XXX */
  1219. #ifdef WITH_READLINE
  1220. static int
  1221. EventHook ()
  1222. {
  1223.   if (errorInCmd)        /* XXX Reset tty */
  1224.     {
  1225.       errorInCmd = 0;
  1226.       PyErr_Restore (excInCmd, valInCmd, trbInCmd);
  1227.       excInCmd = valInCmd = trbInCmd = NULL;
  1228.       PyErr_Print ();
  1229.      }
  1230.   if (Tk_GetNumMainWindows() > 0)
  1231.     Tk_DoOneEvent (TK_DONT_WAIT);
  1232.   return 0;
  1233. }
  1234. #endif /* WITH_READLINE */
  1235.  
  1236. static void
  1237. Tkinter_Cleanup ()
  1238. {
  1239. /* This segfault with Tk 4.0 beta and seems unnecessary there as well */
  1240. #if TK_MAJOR_VERSION < 4
  1241.   /* XXX rl_deprep_terminal is static, damned! */
  1242.   while (tkMainWindowList != 0)
  1243.     Tk_DestroyWindow (tkMainWindowList->win);
  1244. #endif
  1245. }
  1246.  
  1247. void
  1248. init_tkinter ()
  1249. {
  1250.   static inited = 0;
  1251.  
  1252. #ifdef WITH_READLINE
  1253.   extern int (*rl_event_hook) ();
  1254. #endif /* WITH_READLINE */
  1255.   PyObject *m, *d, *v;
  1256.  
  1257.   m = Py_InitModule ("_tkinter", moduleMethods);
  1258.  
  1259.   d = PyModule_GetDict (m);
  1260.   Tkinter_TclError = Py_BuildValue ("s", "TclError");
  1261.   PyDict_SetItemString (d, "TclError", Tkinter_TclError);
  1262.  
  1263.   v = Py_BuildValue ("i", TK_READABLE);
  1264.   PyDict_SetItemString (d, "READABLE", v);
  1265.   v = Py_BuildValue ("i", TK_WRITABLE);
  1266.   PyDict_SetItemString (d, "WRITABLE", v);
  1267.   v = Py_BuildValue ("i", TK_EXCEPTION);
  1268.   PyDict_SetItemString (d, "EXCEPTION", v);
  1269.   v = Py_BuildValue ("i", TK_X_EVENTS);
  1270.   PyDict_SetItemString (d, "X_EVENTS", v);
  1271.   v = Py_BuildValue ("i", TK_FILE_EVENTS);
  1272.   PyDict_SetItemString (d, "FILE_EVENTS", v);
  1273.   v = Py_BuildValue ("i", TK_TIMER_EVENTS);
  1274.   PyDict_SetItemString (d, "TIMER_EVENTS", v);
  1275.   v = Py_BuildValue ("i", TK_IDLE_EVENTS);
  1276.   PyDict_SetItemString (d, "IDLE_EVENTS", v);
  1277.   v = Py_BuildValue ("i", TK_ALL_EVENTS);
  1278.   PyDict_SetItemString (d, "ALL_EVENTS", v);
  1279.   v = Py_BuildValue ("i", TK_DONT_WAIT);
  1280.   PyDict_SetItemString (d, "DONT_WAIT", v);
  1281.   v = Py_BuildValue ("s", TK_VERSION);
  1282.   PyDict_SetItemString (d, "TK_VERSION", v);
  1283.   v = Py_BuildValue ("s", TCL_VERSION);
  1284.   PyDict_SetItemString (d, "TCL_VERSION", v);
  1285.  
  1286. #ifdef WITH_READLINE
  1287.   rl_event_hook = EventHook;
  1288. #endif /* WITH_READLINE */
  1289.  
  1290.   if (!inited)
  1291.     {
  1292.       inited = 1;
  1293.       if (Py_AtExit (Tkinter_Cleanup) != 0)
  1294.     fprintf(stderr,
  1295.         "Tkinter: warning: cleanup procedure not registered\n");
  1296.     }
  1297.  
  1298.   if (PyErr_Occurred ())
  1299.     Py_FatalError ("can't initialize module _tkinter");
  1300. #ifdef macintosh
  1301.   TclMacSetEventProc(PyMacConvertEvent);
  1302. #if GENERATINGCFM
  1303.   mac_addlibresources();
  1304. #endif /* GENERATINGCFM */
  1305. #endif /* macintosh */
  1306. }
  1307.  
  1308.  
  1309. #ifdef macintosh
  1310.  
  1311. /*
  1312. ** Anyone who embeds Tcl/Tk on the Mac must define panic().
  1313. */
  1314.  
  1315. void
  1316. panic(char * format, ...)
  1317. {
  1318.     va_list varg;
  1319.     
  1320.     va_start(varg, format);
  1321.     
  1322.     vfprintf(stderr, format, varg);
  1323.     (void) fflush(stderr);
  1324.     
  1325.     va_end(varg);
  1326.  
  1327.     Py_FatalError("Tcl/Tk panic");
  1328. }
  1329.  
  1330. /*
  1331. ** Pass events to SIOUX before passing them to Tk.
  1332. */
  1333.  
  1334. static int
  1335. PyMacConvertEvent(eventPtr)
  1336.     EventRecord *eventPtr;
  1337. {
  1338.   if (SIOUXHandleOneEvent(eventPtr))
  1339.     return 0; /* Nothing happened to the Tcl event queue */
  1340.   return TkMacConvertEvent(eventPtr);
  1341. }
  1342.  
  1343. #if GENERATINGCFM
  1344.  
  1345. /*
  1346. ** Additional Mac specific code for dealing with shared libraries.
  1347. */
  1348.  
  1349. #include <Resources.h>
  1350. #include <CodeFragments.h>
  1351.  
  1352. static int loaded_from_shlib = 0;
  1353. static FSSpec library_fss;
  1354.  
  1355. /*
  1356. ** If this module is dynamically loaded the following routine should
  1357. ** be the init routine. It takes care of adding the shared library to
  1358. ** the resource-file chain, so that the tk routines can find their
  1359. ** resources.
  1360. */
  1361. OSErr pascal
  1362. init_tkinter_shlib(InitBlockPtr data)
  1363. {
  1364.     __sinit();
  1365.     if ( data == nil ) return noErr;
  1366.     if ( data->fragLocator.where == kOnDiskFlat ) {
  1367.         library_fss = *data->fragLocator.u.onDisk.fileSpec;
  1368.         loaded_from_shlib = 1;
  1369.     } else if ( data->fragLocator.where == kOnDiskSegmented ) {
  1370.         library_fss = *data->fragLocator.u.inSegs.fileSpec;
  1371.         loaded_from_shlib = 1;
  1372.     }
  1373.     return noErr;
  1374. }
  1375.  
  1376. /*
  1377. ** Insert the library resources into the search path. Put them after
  1378. ** the resources from the application. Again, we ignore errors.
  1379. */
  1380. static
  1381. mac_addlibresources()
  1382. {
  1383.     if ( !loaded_from_shlib ) 
  1384.         return;
  1385.     (void)FSpOpenResFile(&library_fss, fsRdPerm);
  1386. }
  1387.  
  1388. #endif /* GENERATINGCFM */
  1389. #endif /* macintosh */
  1390.